#pragma once

#include <iostream>
#include <unistd.h>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cstdio>
#include "comm.hpp"

#define EXIT_SIG(exit_signal)     \
    do                            \
    {                             \
        perror(exit_signal "\n"); \
        exit(EXIT_FAILURE);       \
    } while (0);

#define CREATE "create"
#define USER "user"

const char *PathName = ".";
const int Proj_id = (IPC_CREAT | IPC_EXCL | 0666);
const int Size = 1024;
const int gdefaultid = -1;

class Shm
{
private:
    void Create(int flag)
    {
        int ret = shmget(_key, _Size, flag);
        if (ret == -1)
        {
            std::cout << "Key是" << _key << std::endl;
            EXIT_SIG("共享内存创建失败");
        }
        else
        {
            _shm = ret;
            std::cout << "共享内存创建成功" << "Key是" << _key << std::endl;
        }
    }

    void create()
    {
        Create(Proj_id);
    }

    void Get()
    {
        Create(IPC_CREAT);
    }

    // 挂接
    void Attach()
    {
        _start_address = (void *)shmat(_shm, nullptr, 0);
        if (_start_address == (void *)(-1))
        {
            EXIT_SIG("Attach failed");
        }
        else
        {
            std::cout << "Attch success" << std::endl;
        }
    }

    //结束挂接
    void Detach()
    {
        int ret=shmdt(_start_address);
        if(ret<0)
        {
            EXIT_SIG("Detach failed");
        }
        else
        {
            std::cout<<"Detach success"<<std::endl;
        }
    }
    void destroy()
    {
        Detach();
        // if (_shm == -1)
        //     return;
        // shmctl
        // if(CREATE==_usertype)
        // {
            int ret = shmctl(_shm, IPC_RMID, nullptr);
            if (ret < 0)
            {
                EXIT_SIG("destroy failed");
            }
            else
            {
                std::cout << "destroy success" << std::endl;
            }

        // }
    }
public:
    // 保证创建的一定是一个全新的共享内存
    Shm(const std::string& usertype, const std::string& pathname,int flag)
    : _shm(gdefaultid),
      _Size(Size),
      _start_address(nullptr),
      _usertype(usertype)
    {
        _key = ftok(pathname.c_str(), flag);
        if (_key == -1)
        {
            EXIT_SIG("生成 key 失败");
        }
        if (_usertype == CREATE)
        {
            create();
        }
        else if (_usertype == USER)
        {
            Get();
        }
        else{}
        Attach();
    }

    void *VirtualAddress()
    {
        std::cout << "_start_address:" << _start_address << std::endl;
        return _start_address;
    }

    int GetSize()
    {
        return _Size;
    }

    void Attr()
    {
        struct shmid_ds ds;
        int n = shmctl(_shm, IPC_STAT, &ds); // ds:输出型参数
        printf("shm_segsz: %ld\n", ds.shm_segsz);
        printf("key: 0x%x\n", ds.shm_perm.__key);
    }

    ~Shm()
    {
        destroy();
    }

private:
    int _shm;  // 共享内存标识符int
    int _Size; // 创建共享内存大小
    key_t _key;
    void *_start_address;  // 起始地址
    std::string _usertype; // 用户类型
};